package com.nullpointer.xchatfinal.fragment;

import java.util.ArrayList;
import java.util.List;

import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.nullpointer.xchatfinal.MainActivity;
import com.nullpointer.xchatfinal.R;
import com.nullpointer.xchatfinal.adapter.NearbyAdapter;
import com.nullpointer.xchatfinal.object.Nearby;
import com.nullpointer.xchatfinal.object.User;
import com.nullpointer.xchatfinal.utils.Common;
import com.nullpointer.xchatfinal.utils.DataManager;
import com.nullpointer.xchatfinal.utils.KiraGameLog;
import com.nullpointer.xchatfinal.utils.Utils;
import com.quickblox.core.Consts;
import com.quickblox.core.QBEntityCallbackImpl;
import com.quickblox.location.QBLocations;
import com.quickblox.location.model.QBLocation;
import com.quickblox.location.request.QBLocationRequestBuilder;
import com.quickblox.location.request.SortField;
import com.quickblox.location.request.SortOrder;

public class NearbyFragment extends Fragment implements
		GoogleApiClient.ConnectionCallbacks,
		GoogleApiClient.OnConnectionFailedListener {

	// Location
	// private LocationClient mLocationClient;
	private GoogleApiClient client = null;
	private Location location;
	// private LocationRequest mLocationRequest;

	// Milliseconds per second
	// private static final int MILLISECONDS_PER_SECOND = 1000;
	// // Update frequency in seconds
	// public static final int UPDATE_INTERVAL_IN_SECONDS = 5 * 60;
	// // Update frequency in milliseconds
	// private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND
	// * UPDATE_INTERVAL_IN_SECONDS;
	// // The fastest update frequency, in seconds
	// private static final int FASTEST_INTERVAL_IN_SECONDS = 1;
	// // A fast frequency ceiling in milliseconds
	// private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND
	// * FASTEST_INTERVAL_IN_SECONDS;
	protected static final String NOT_FOUND = "not found";

	//

	private ListView lvUsers;
	private List<Nearby> data = new ArrayList<Nearby>();
	private NearbyAdapter adapter;
	private int page = 1;
	private boolean isLoadDone = true;
	private boolean canLoadMore = false;
	private final int SIZE_PER_PAGE = 50;
	private final int DISTANCE_IN_KM = 1000 * 10;
	private View footerView;

	public static NearbyFragment newInstance() {
		NearbyFragment f = new NearbyFragment();
		return f;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View view = inflater
				.inflate(R.layout.fragment_nearby, container, false);
		footerView = inflater.inflate(R.layout.view_item_load_more, null);
		findViewIds(view);
		init();
		setEvent();
		return view;
	}

	private void init() {
		lvUsers.addFooterView(footerView);
		footerView.setVisibility(View.GONE);
		adapter = new NearbyAdapter(getActivity(), data);
		lvUsers.setAdapter(adapter);
		// mLocationRequest = LocationRequest.create();
		// // Use high accuracy
		// mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
		// // Set the update interval to 5 seconds
		// mLocationRequest.setInterval(UPDATE_INTERVAL);
		// // Set the fastest update interval to 1 second
		// mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
		client = new GoogleApiClient.Builder(getActivity())
				.addApi(LocationServices.API).addConnectionCallbacks(this)
				.addOnConnectionFailedListener(this).build();
		// mLocationClient = new LocationClient(getActivity(), this, this);
		client.connect();
		// refreshData();
	}

	private void getNearbyUser(Location currentLocation, int page) {
		if (currentLocation == null) {
			hideLoadingAnimation();
			showLocationError();
			return;
		}
		showLoadingAnimation();
		double latitude = currentLocation.getLatitude();
		double longitude = currentLocation.getLongitude();

		QBLocationRequestBuilder locationRequestBuilder = new QBLocationRequestBuilder();
		locationRequestBuilder.setSort(SortField.CREATED_AT,
				SortOrder.DESCENDING);
		locationRequestBuilder.setSort(SortField.DISTANCE, SortOrder.ASCENDING);
		locationRequestBuilder.setRadius(latitude, longitude, DISTANCE_IN_KM);

		locationRequestBuilder.setPage(page);
		locationRequestBuilder.setPerPage(SIZE_PER_PAGE);

		QBLocations.getLocations(locationRequestBuilder,
				new QBEntityCallbackImpl<ArrayList<QBLocation>>() {

					@Override
					public void onSuccess(ArrayList<QBLocation> locations,
							Bundle params) {
						KiraGameLog.d(">>> get nearby user:"
								+ locations.toString());
						if (locations == null || locations.size() == 0) {
							isLoadDone = true;
							canLoadMore = false;
							hideLoadingAnimation();
						} else {
							for (QBLocation qbLocation : locations) {
								User user = Utils
										.convertQBUserToUser(qbLocation
												.getUser());
								float distance = getDistanceTo(
										qbLocation.getLatitude(),
										qbLocation.getLongitude());
								data.add(new Nearby(distance, user));
							}
							adapter.notifyDataSetChanged();
							int totalEntries = params
									.getInt(Consts.TOTAL_ENTRIES);
							int currentPageRequest = params
									.getInt(Consts.CURR_PAGE);
							int perPage = params.getInt(Consts.PER_PAGE);
							int totalPage = (totalEntries / perPage) + 1;

							KiraGameLog.d("totalEntries: " + totalEntries
									+ " currentPageRequest "
									+ currentPageRequest + " totalPage "
									+ totalPage + " data size " + data.size());

							hideLoadingAnimation();
							isLoadDone = true;
							if (currentPageRequest < totalPage) {
								canLoadMore = true;
							} else {
								canLoadMore = false;
							}

						}

					}

					@Override
					public void onError(List<String> errors) {
						KiraGameLog.d(">>> get nearby user error:" + errors);
						hideLoadingAnimation();
						isLoadDone = true;
						canLoadMore = false;
					}
				});
	}

	private void updateUserLocation(final Location currentLocation) {
		int userID = DataManager.getInstance(getActivity()).getCurrentUser()
				.getUserID();
		QBLocationRequestBuilder locationRequestBuilder = new QBLocationRequestBuilder();
		locationRequestBuilder.setUserId(userID);
		locationRequestBuilder.setPage(1);
		locationRequestBuilder.setPerPage(1);

		QBLocations.getLocations(locationRequestBuilder,
				new QBEntityCallbackImpl<ArrayList<QBLocation>>() {

					@Override
					public void onSuccess(ArrayList<QBLocation> locations,
							Bundle params) {
						KiraGameLog.d("get location by id " + locations);
						updateLocation(locations.get(0), currentLocation);
					}

					@Override
					public void onError(List<String> errors) {
						KiraGameLog.d("get location by id fail" + errors);
						if (errors.get(0).contains(NOT_FOUND)) {
							createNewLocation(currentLocation);
						}
					}
				});
	}

	protected void updateLocation(QBLocation qbLocation,
			Location currentLocation) {
		qbLocation.setLatitude(currentLocation.getLatitude());
		qbLocation.setLongitude(currentLocation.getLongitude());
		QBLocations.updateLocation(qbLocation,
				new QBEntityCallbackImpl<QBLocation>() {
					@Override
					public void onSuccess(QBLocation qbLocation, Bundle args) {
						KiraGameLog.d("Update Location is: " + qbLocation);
					}

					@Override
					public void onError(List<String> errors) {
						KiraGameLog.d("Update Location error " + errors);
					}
				});
	}

	protected void createNewLocation(Location currentLocation) {
		final QBLocation location = new QBLocation(
				currentLocation.getLatitude(), currentLocation.getLongitude(),
				"I'm here");
		QBLocations.createLocation(location,
				new QBEntityCallbackImpl<QBLocation>() {

					@Override
					public void onSuccess(QBLocation qbLocation, Bundle args) {
						KiraGameLog.d("Location is: " + qbLocation);

					}

					@Override
					public void onError(List<String> errors) {
						KiraGameLog.d("create location error");
					}
				});
	}

	private void showLocationError() {
		try {
			((MainActivity) getActivity()).showNotice(false,
					"Can't get your location!", "SETTING",
					new OnClickListener() {

						@Override
						public void onClick(View v) {
							Intent viewIntent = new Intent(
									Settings.ACTION_LOCATION_SOURCE_SETTINGS);
							startActivityForResult(viewIntent,
									Common.RequestCode.LOCATION_SETTING);
						}
					});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void hideLocationError() {
		try {
			((MainActivity) getActivity()).hideNotice();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void refreshData() {
		isLoadDone = true;
		canLoadMore = false;
		page = 1;
		clearUserData();
		showLoadingInfo();
		getNearbyUser(location, page);
	}

	private void setEvent() {
		lvUsers.setOnScrollListener(new OnScrollListener() {

			@Override
			public void onScrollStateChanged(AbsListView view, int scrollState) {

			}

			@Override
			public void onScroll(AbsListView view, int firstVisibleItem,
					int visibleItemCount, int totalItemCount) {
				if (view.getLastVisiblePosition() >= totalItemCount - 1) {
					if (!canLoadMore) {
						return;
					}
					moreLoad();
				}
			}
		});
	}

	private void findViewIds(View view) {
		lvUsers = (ListView) view.findViewById(R.id.lv_users);
	}

	private void clearUserData() {
		data.clear();
		adapter.notifyDataSetChanged();
	}

	public void moreLoad() {
		if (!isLoadDone) {
			return;
		}
		KiraGameLog.d("load more with page " + page);
		isLoadDone = false;
		page++;
		showLoadMoreView();
		getNearbyUser(location, page);
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		switch (requestCode) {
		case Common.RequestCode.LOCATION_SETTING:
			client = new GoogleApiClient.Builder(getActivity())
					.addApi(LocationServices.API).addConnectionCallbacks(this)
					.addOnConnectionFailedListener(this).build();
			client.connect();
			break;
		default:
			break;
		}
	}

	@Override
	public void onConnectionFailed(ConnectionResult result) {
		KiraGameLog.d("Location onConnectionFailed " + result);
		showLocationError();
	}

	@Override
	public void onConnected(Bundle connectionHint) {
		KiraGameLog.d("Location onConnected " + connectionHint);
		// mLocationClient.requestLocationUpdates(mLocationRequest, this);
		Location currentLocation = getCurrentLocation();
		if (currentLocation != null) {
			KiraGameLog.d("my location " + currentLocation);
			updateUserLocation(currentLocation);
			refreshData();
			hideLocationError();
		} else {
			hideLoadingAnimation();
			showLocationError();
		}
	}

	@Override
	public void onConnectionSuspended(int reason) {
		KiraGameLog.d("Location onConnectionSuspended " + reason);
	}

	public Location getCurrentLocation() {
		if (location == null) {
			location = LocationServices.FusedLocationApi
					.getLastLocation(client);
		}
		return location;
	}

	@Override
	public void onDestroy() {
		if (client != null) {
			client.disconnect();
		}
		super.onDestroy();
	}

	private void showLoadingInfo() {
		try {
			((MainActivity) getActivity()).showInfo("loading data...", true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void showLoadMoreView() {
		footerView.setVisibility(View.VISIBLE);
	}

	public void showLoadingAnimation() {
		try {
			((MainActivity) getActivity()).startRefeshAnimation();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void hideLoadingAnimation() {
		try {
			((MainActivity) getActivity()).stopRefeshAnimation();
			((MainActivity) getActivity()).hideInfo();
		} catch (Exception e) {
			e.printStackTrace();
		}
		footerView.setVisibility(View.GONE);
	}

	private float getDistanceTo(double lat, double lng) {
		Location location = getCurrentLocation();
		if (location == null) {
			return 0;
		}
		Location locationA = new Location("point A");
		locationA.setLatitude(location.getLatitude());
		locationA.setLongitude(location.getLongitude());
		Location locationB = new Location("point B");
		locationB.setLatitude(lat);
		locationB.setLongitude(lng);
		return locationA.distanceTo(locationB);
	}

}
